home *** CD-ROM | disk | FTP | other *** search
/ Freelog Special Edition 10 / FreelogHS10.iso / Buzz / Buzz_Advanced_Pack.exe / {app} / Dev / Delay / Delay.cpp next >
C/C++ Source or Header  |  2001-08-27  |  10KB  |  558 lines

  1.  
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5. #include <assert.h>
  6. #include <math.h>
  7. #include "../../MachineInterface.h"
  8.  
  9. double const SilentEnough = log(1.0 / 32768);
  10.  
  11. #define MAX_TAPS        8
  12.  
  13. CMachineParameter const paraLength = 
  14.     pt_word,                                        // type
  15.     "Length",
  16.     "Length in length units",                        // description
  17.     1,                                                // MinValue    
  18.     32768,                                            // MaxValue
  19.     65535,                                            // NoValue
  20.     MPF_STATE,                                        // Flags
  21.     3
  22. };
  23.  
  24. #define UNIT_TICK        0
  25. #define UNIT_MS            1
  26. #define UNIT_SAMPLE        2
  27. #define UNIT_256        3
  28.  
  29. CMachineParameter const paraDryThru = 
  30.     pt_switch,                                        // type
  31.     "Dry thru",
  32.     "Dry thru (1 = yes, 0 = no)",                    // description
  33.     -1,                                                // MinValue    
  34.     -1,                                                // MaxValue
  35.     SWITCH_NO,                                        // NoValue
  36.     MPF_STATE,                                        // Flags
  37.     SWITCH_ON
  38. };
  39.  
  40. CMachineParameter const paraUnit =
  41.     pt_byte,                                         // type
  42.     "Length unit",
  43.     "Length unit (0 = tick (default), 1 = ms, 2 = sample, 3 = 256th of tick)",        
  44.     0,                                                // MinValue    
  45.     3,                                                // MaxValue
  46.     0xff,                                            // NoValue
  47.     MPF_STATE,                                        // Flags
  48.     0
  49. };
  50.  
  51.  
  52. CMachineParameter const paraFeedback = 
  53.     pt_byte,                                        // type
  54.     "Feedback",
  55.     "Feedback (00 = -100%, 40=0%, 80 = 100%)",        // description
  56.     0,                                                // MinValue    
  57.     128,                                            // MaxValue
  58.     255,                                            // NoValue
  59.     MPF_STATE,                                        // Flags
  60.     0x60
  61. };
  62.  
  63. CMachineParameter const paraWetOut = 
  64.     pt_byte,                                        // type
  65.     "Wet out",
  66.     "Wet out (00 = 0%, 80 = 100%)",                    // description
  67.     0,                                                // MinValue    
  68.     128,                                            // MaxValue
  69.     255,                                            // NoValue
  70.     MPF_STATE,                                        // Flags
  71.     0x30
  72. };
  73.  
  74.  
  75. CMachineParameter const *pParameters[] = 
  76.     ¶DryThru,
  77.     ¶Length,
  78.     ¶Unit,
  79.     ¶Feedback,
  80.     ¶WetOut,
  81. };
  82.  
  83. CMachineAttribute const attrMaxDelay = 
  84. {
  85.     "Max Delay (ms)",
  86.     1,
  87.     100000,
  88.     1000    
  89. };
  90.  
  91. CMachineAttribute const *pAttributes[] = 
  92. {
  93.     &attrMaxDelay
  94. };
  95.  
  96. #pragma pack(1)
  97.  
  98. class gvals
  99. {
  100. public:
  101.     byte drythru;
  102. };
  103.  
  104. class tvals
  105. {
  106. public:
  107.     word length;
  108.     byte unit;
  109.     byte feedback;
  110.     byte wetout;
  111. };
  112.  
  113. class avals
  114. {
  115. public:
  116.     int maxdelay;
  117. };
  118.  
  119. #pragma pack()
  120.  
  121. CMachineInfo const MacInfo = 
  122. {
  123.     MT_EFFECT,                                // type
  124.     MI_VERSION,
  125.     0,                                        // flags
  126.     1,                                        // min tracks
  127.     MAX_TAPS,                                // max tracks
  128.     1,                                        // numGlobalParameters
  129.     4,                                        // numTrackParameters
  130.     pParameters,
  131.     1,
  132.     pAttributes,
  133. #ifdef _DEBUG
  134.     "Jeskola Delay (Debug build)",            // name
  135. #else
  136.     "Jeskola Delay",
  137. #endif
  138.     "Delay",                                // short name
  139.     "Oskari Tammelin",                        // author
  140.     NULL
  141. };
  142.  
  143. class CTrack
  144. {
  145. public:
  146.     float *Buffer;
  147.     int Length;
  148.     int Pos;
  149.     float Feedback;
  150.     float WetOut;
  151.     int Unit;
  152. };
  153.  
  154.  
  155. class mi : public CMachineInterface
  156. {
  157. public:
  158.     mi();
  159.     virtual ~mi();
  160.  
  161.     virtual void Init(CMachineDataInput * const pi);
  162.     virtual void Tick();
  163.     virtual bool Work(float *psamples, int numsamples, int const mode);
  164.  
  165.     virtual void SetNumTracks(int const n);
  166.  
  167.     virtual void AttributesChanged();
  168.  
  169.     virtual char const *DescribeValue(int const param, int const value);
  170.  
  171. private:
  172.     void InitTrack(int const i);
  173.     void ResetTrack(int const i);
  174.  
  175.     void TickTrack(CTrack *pt, tvals *ptval);
  176.     void WorkTrack(CTrack *pt, float *pin, float *pout, int numsamples, int const mode);
  177.  
  178. private:
  179.     int MaxDelay;    // in samples
  180.     int IdleCount;    // in samples
  181.     int DelayTime;
  182.     bool IdleMode;
  183.     bool DryThru;
  184.  
  185. private:
  186.     int numTracks;
  187.     CTrack Tracks[MAX_TAPS];
  188.  
  189.     avals aval;
  190.     gvals gval;
  191.     tvals tval[MAX_TAPS];
  192.  
  193.  
  194. };
  195.  
  196. DLL_EXPORTS
  197.  
  198. mi::mi()
  199. {
  200.     GlobalVals = &gval;
  201.     TrackVals = tval;
  202.     AttrVals = (int *)&aval;
  203. }
  204.  
  205. mi::~mi()
  206. {
  207.     for (int c = 0; c < MAX_TAPS; c++)
  208.     {
  209.         delete[] Tracks[c].Buffer;
  210.     }
  211. }
  212.  
  213. char const *mi::DescribeValue(int const param, int const value)
  214. {
  215.     static char txt[16];
  216.  
  217.     switch(param)
  218.     {
  219.     case 1:        // length
  220.         return NULL;
  221.         break;
  222.     case 2:        // unit
  223.         switch(value)
  224.         {
  225.         case 0: return "tick";
  226.         case 1: return "ms";
  227.         case 2: return "sample";
  228.         case 3: return "tick/256";
  229.         }
  230.         break;
  231.     case 3:        // feedback
  232.         sprintf(txt, "%.1f%%", (double)(value-64) * (100.0 / 64.0));
  233.         break;
  234.     case 4:        // wetout
  235.         sprintf(txt, "%.1f%%", (double)value * (100.0 / 128.0));
  236.         break;
  237.     default:
  238.         return NULL;
  239.     }
  240.  
  241.     return txt;
  242. }
  243.  
  244.  
  245.  
  246. void mi::Init(CMachineDataInput * const pi)
  247. {
  248.     numTracks = 1;
  249.     DryThru = true;
  250.  
  251.     for (int c = 0; c < MAX_TAPS; c++)
  252.     {
  253.         Tracks[c].Buffer = NULL;
  254.         Tracks[c].Unit = UNIT_TICK;
  255.         Tracks[c].Length = pMasterInfo->SamplesPerTick * 3;
  256.         Tracks[c].Pos = 0;
  257.         Tracks[c].Feedback = 0.3f;
  258.         Tracks[c].WetOut = 0;
  259.     }
  260.  
  261.     Tracks[0].WetOut = 0.3f;    // enable first track
  262.  
  263.     IdleMode = true;
  264.     IdleCount = 0;
  265.  
  266. }
  267.  
  268. void mi::AttributesChanged()
  269. {
  270.     MaxDelay = (int)(pMasterInfo->SamplesPerSec * (aval.maxdelay / 1000.0));
  271.     for (int c = 0; c < numTracks; c++)
  272.         InitTrack(c);
  273. }
  274.  
  275.  
  276. void mi::SetNumTracks(int const n)
  277. {
  278.     if (numTracks < n)
  279.     {
  280.         for (int c = numTracks; c < n; c++)
  281.             InitTrack(c);
  282.     }
  283.     else if (n < numTracks)
  284.     {
  285.         for (int c = n; c < numTracks; c++)
  286.             ResetTrack(c);
  287.     
  288.     }
  289.     numTracks = n;
  290.  
  291. }
  292.  
  293.  
  294. void mi::InitTrack(int const i)
  295. {
  296.     delete[] Tracks[i].Buffer;
  297.     Tracks[i].Buffer = new float [MaxDelay];
  298.     memset(Tracks[i].Buffer, 0, MaxDelay*4);
  299.     Tracks[i].Pos = 0;
  300.     if (Tracks[i].Length > MaxDelay)
  301.         Tracks[i].Length = MaxDelay;
  302. }
  303.  
  304. void mi::ResetTrack(int const i)
  305. {
  306.     delete[] Tracks[i].Buffer;
  307.     Tracks[i].Buffer = NULL;
  308. }
  309.  
  310.  
  311. void mi::TickTrack(CTrack *pt, tvals *ptval)
  312. {
  313.     if (ptval->unit != paraUnit.NoValue)
  314.         pt->Unit = ptval->unit;
  315.  
  316.     if (ptval->length != paraLength.NoValue)
  317.     {
  318.         switch(pt->Unit)
  319.         {
  320.         case UNIT_MS:
  321.             pt->Length = (int)(pMasterInfo->SamplesPerSec * (ptval->length / 1000.0));
  322.             if (pt->Length < 1)
  323.                 pt->Length = 1;
  324.             break;
  325.         case UNIT_SAMPLE:
  326.             pt->Length = ptval->length;
  327.             break;
  328.         case UNIT_TICK:
  329.             pt->Length = pMasterInfo->SamplesPerTick * ptval->length;
  330.             break;
  331.         case UNIT_256:
  332.             pt->Length = (pMasterInfo->SamplesPerTick * ptval->length) >> 8;
  333.             if (pt->Length < 1)
  334.                 pt->Length = 1;
  335.             break;
  336.         }
  337.  
  338.     }
  339.  
  340.     if (pt->Length > MaxDelay)
  341.     {
  342.         pt->Length = MaxDelay;
  343.     }
  344.     
  345.  
  346.     if (pt->Pos >= pt->Length)
  347.         pt->Pos = 0;
  348.  
  349.     if (ptval->feedback != paraFeedback.NoValue)
  350.     {
  351.         pt->Feedback = (float)((ptval->feedback - 64) * (1.0 / 64.0)); 
  352.     }
  353.  
  354.     if (ptval->wetout != paraWetOut.NoValue)
  355.         pt->WetOut = (float)(ptval->wetout * (1.0 / 128.0));
  356.     
  357. }
  358.  
  359. void mi::Tick()
  360. {
  361.     for (int c = 0; c < numTracks; c++)
  362.         TickTrack(Tracks + c, tval+c);
  363.  
  364.  
  365.     // find max delay time slow we know when to stop wasting CPU time
  366.     int maxdt = 0;
  367.     for (c = 0; c < numTracks; c++)
  368.     {
  369.         int dt = Tracks[c].Length + (int)(SilentEnough / log(fabs(Tracks[c].Feedback)) * Tracks[c].Length); 
  370.         if (dt > maxdt)
  371.             maxdt = dt;
  372.     }
  373.     
  374.     DelayTime = maxdt;
  375.  
  376.  
  377.     
  378.     if (gval.drythru != SWITCH_NO)
  379.         DryThru = gval.drythru != 0;
  380. }
  381.  
  382. #pragma optimize ("a", on) 
  383.  
  384. static void DoWork(float *pin, float *pout, float *pbuf, int c, double const wetout, double const feedback)
  385. {
  386.     do
  387.     {
  388.  
  389.         double delay = *pbuf;
  390.         *pbuf++ = (float)(feedback * delay + *pin++);
  391.         *pout++ += (float)(delay * wetout);
  392.  
  393.     } while(--c);
  394. }
  395.  
  396. static void DoWorkNoFB(float *pin, float *pout, float *pbuf, int c, double const wetout)
  397. {
  398.     do
  399.     {
  400.  
  401.         double delay = *pbuf;
  402.         *pbuf++ = (float)(*pin++);
  403.         *pout++ += (float)(delay * wetout);
  404.  
  405.     } while(--c);
  406. }
  407.  
  408. static void DoWorkNoInput(float *pout, float *pbuf, int c, double const wetout, double const feedback)
  409. {
  410.     do
  411.     {
  412.         double delay = *pbuf;
  413.         *pbuf++ = (float)(feedback * delay);
  414.         *pout++ += (float)(delay * wetout);
  415.  
  416.     } while(--c);
  417. }
  418.  
  419.  
  420.  
  421. static void DoWorkNoInputNoFB(float *pout, float *pbuf, int c, double const wetout)
  422. {
  423.  
  424.     do
  425.     {
  426.         double delay = *pbuf;
  427.         *pbuf++ = 0;
  428.         *pout++ += (float)(delay * wetout);
  429.     } while(--c);
  430. }
  431.  
  432. static void DoWorkNoInputNoOutput(float *pbuf, int c, double const feedback)
  433. {
  434.     do
  435.     {
  436.         *pbuf = (float)(*pbuf * feedback);
  437.         pbuf++;
  438.     } while(--c);
  439. }
  440.  
  441. static void DoWorkNoOutput(float *pin, float *pbuf, int c, double const feedback)
  442. {
  443.     do
  444.     {
  445.  
  446.         double delay = *pbuf;
  447.         double dry = *pin++;
  448.         *pbuf++ = (float)(feedback * delay + dry);
  449.  
  450.     } while(--c);
  451. }
  452.  
  453. static void DoWorkNoOutputNoFB(float *psamples, float *pbuf, int c)
  454. {
  455.     memcpy(pbuf, psamples, c*4);
  456. }
  457.  
  458.  
  459. #pragma optimize ("", on)
  460.  
  461.  
  462. void mi::WorkTrack(CTrack *pt, float *pin, float *pout, int numsamples, int const mode)
  463. {
  464.     do
  465.     {
  466.         int count = __min(numsamples, pt->Length - pt->Pos);
  467.  
  468.         if (count > 0)
  469.         {
  470.             if (mode == WM_NOIO)
  471.             {
  472.                 if (pt->Feedback != 0)
  473.                     DoWorkNoInputNoOutput(pt->Buffer + pt->Pos, count, pt->Feedback);
  474.             }
  475.             else if (mode == WM_WRITE)
  476.             {
  477.                 if (pt->Feedback != 0)
  478.                     DoWorkNoInput(pout, pt->Buffer + pt->Pos, count, pt->WetOut, pt->Feedback);
  479.                 else
  480.                     DoWorkNoInputNoFB(pout, pt->Buffer + pt->Pos, count, pt->WetOut);
  481.             }
  482.             else if (mode == WM_READ)
  483.             {
  484.                 if (pt->Feedback != 0)
  485.                     DoWorkNoOutput(pin, pt->Buffer + pt->Pos, count, pt->Feedback);
  486.                 else
  487.                     DoWorkNoOutputNoFB(pin, pt->Buffer + pt->Pos, count);
  488.  
  489.             }
  490.             else
  491.             {
  492.                 if (pt->Feedback != 0)
  493.                     DoWork(pin, pout, pt->Buffer + pt->Pos, count, pt->WetOut, pt->Feedback);
  494.                 else
  495.                     DoWorkNoFB(pin, pout, pt->Buffer + pt->Pos, count, pt->WetOut);
  496.             }
  497.             
  498.             pin += count;
  499.             pout += count;
  500.             numsamples -= count;
  501.             pt->Pos += count;
  502.         } 
  503.  
  504.         if (pt->Pos == pt->Length)
  505.             pt->Pos = 0;
  506.  
  507.     } while(numsamples > 0);
  508.  
  509. }
  510.  
  511. bool mi::Work(float *psamples, int numsamples, int const mode)
  512. {
  513.     if (mode & WM_READ)
  514.     {
  515.         IdleMode = false;
  516.         IdleCount = 0;
  517.     }
  518.     else
  519.     {
  520.         if (IdleMode)
  521.         {
  522.             return false;
  523.         }
  524.         else
  525.         {
  526.             IdleCount += numsamples;
  527.             if (IdleCount >= DelayTime + MAX_BUFFER_LENGTH)
  528.             {
  529.                 // clear all buffers
  530.                 for (int c = 0; c < numTracks; c++)
  531.                     memset(Tracks[c].Buffer, 0, Tracks[c].Length*4);
  532.                 IdleMode = true;
  533.             }
  534.         }
  535.     }
  536.  
  537.     float *paux = pCB->GetAuxBuffer();
  538.  
  539.     if (mode & WM_READ)
  540.         memcpy(paux, psamples, numsamples*4);
  541.  
  542.     if (!DryThru || !(mode & WM_READ))
  543.         memset(psamples, 0, numsamples*4);
  544.  
  545.     for (int c = 0; c < numTracks; c++)
  546.         WorkTrack(Tracks + c, paux, psamples, numsamples, mode);
  547.  
  548.     return true;
  549. }
  550.  
  551.  
  552.